package cn.mw.cmdb.entity;

import cn.mw.cmdb.param.ImportContextParam;
import cn.mw.cmdb.param.InstanceSearchParam;
import cn.mw.cmdb.param.MwRelationPropertyType;
import cn.mw.cmdb.service.impl.CmdbServiceManage;
import cn.mw.cmdb.service.impl.CustomModelServiceImpl;
import cn.mw.cmdb.service.impl.InstanceServiceImpl;
import cn.mw.cmdb.service.impl.InstanceViewImpl;
import cn.mw.components.mongodb.entity.CriteriaOpsType;
import cn.mw.microMonitorCommon.entity.cmdb.ModelExportDataInfoParam;
import cn.mw.microMonitorCommon.entity.cmdb.MwImportResultParam;
import cn.mw.microMonitorCommon.util.ListMapObjUtils;
import cn.mw.microMonitorCommon.util.SpringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.nacos.shaded.com.google.gson.Gson;
import com.google.common.base.Strings;
import com.google.gson.reflect.TypeToken;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

import static cn.mw.cmdb.entity.PropertyTypeExtMultiple.sortMapByKey;
import static cn.mw.cmdb.entity.PropertyTypeMoney.isNumeric;
import static cn.mw.cmdb.processor.MonitorValue.InStanceNameKey;
import static cn.mw.cmdb.service.impl.InstanceViewImpl.*;

@Slf4j
public class PropertyTypeExtSingle extends PropertyType<PropertyTypeExtSingle, Object> implements MwRelationPropertyType {
    public static final String ID = "extSingle";
    private static final String FirstDropdownKey = "modelId";
    private static Map<String, List> finalList = new HashMap<>();

    private static final String SecodDropdownKey = "fieldId";

    public PropertyTypeExtSingle() {
        setId(ID);
        setName("外部关联(单选)");
        setSortNum(4);
    }

    @Override
    public Criteria doCriteria(CriteriaOpsType opsType, String name, Object value) {
        String relationNamePath = getRelationNamePath(name, ID);
        String relationIdPath = getNotPrefixRelationIdPath(name);
        Criteria criteria = null;

        switch (opsType) {
            case is:
                if (isNumeric(value) && strValueConvert(value).length() > 10) {
                    criteria = new Criteria(relationIdPath).is(value.toString());
                } else {
                    criteria = new Criteria(relationNamePath).is(value);
                }
                break;
            case in:
                if (value instanceof List) {
                    List vals = (List) value;
                    if(CollectionUtils.isNotEmpty(vals)){
                        Object obj = vals.get(0);
                        if (isNumeric(obj) && strValueConvert(obj).length() > 10) {
                            criteria = new Criteria(relationIdPath).in(vals);;
                        } else {
                            criteria = new Criteria(relationNamePath).in(vals);
                        }
                    }
                }
                break;
            case like:
                if (isNumeric(value) && strValueConvert(value).length() > 10) {
//                    criteria = new Criteria(relationIdPath).is(value.toString());
                } else {
                    criteria = new Criteria(relationNamePath).regex(strValueConvert(value));
                }
                break;
            case ne:
                if(value != null){
                    if (isNumeric(value) && strValueConvert(value).length() > 10) {
                        criteria = new Criteria(relationIdPath).ne(value.toString());
                    } else {
                        criteria = new Criteria(relationNamePath).ne(value);
                    }
                }else{
                    criteria = new Criteria(relationNamePath).exists(true);
                }
                break;
            case exist:
                if (isNumeric(value) && strValueConvert(value).length() > 10) {
                    criteria = new Criteria(relationIdPath).exists(true);
                } else {
                    criteria = new Criteria(relationNamePath).exists(true);
                }
                break;
            default:
        }
        return criteria;
    }

    @Override
    public CriteriaOpsType getDefaultCriteriaOpsType() {
        return CriteriaOpsType.is;
    }

    @Override
    public Object convertValue(Object value) {
        Gson gson = new Gson();
        TypeToken<Map<String, String>> typeToken = new TypeToken<Map<String, String>>() {
        };
        if (value != null) {
            Map<String, String> map;
            try {
                if (Strings.isNullOrEmpty(strValueConvert(value))) {
                    return "";
                } else if (value instanceof String) {
                    map = gson.fromJson(strValueConvert(value), typeToken.getType());
                } else {
                    map = gson.fromJson(JSON.toJSONString(value), typeToken.getType());
                }
                if (map != null) {
                    Map<String, String> sortMap = sortMapByKey(map);
                    return sortMap;
                }
            } catch (Exception e) {
                return "";
            }

        }
        return null;
    }


    @Override
    public PropertyTypeExtSingle newObj() {
        return new PropertyTypeExtSingle();
    }

    @Override
    public Object listInputOption(PropertyTypeRef propertyTypeRef) throws Exception {
        Map<String, Object> context = propertyTypeRef.getContext();
        List<InstanceInputOption> list = new ArrayList<>();
        if (null != context) {
            CmdbServiceManage cmdbServiceManage = SpringUtils.getBean(CmdbServiceManage.class);
            InstanceServiceImpl instanceService = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
            InstanceSearchParam searchParam = new InstanceSearchParam();

            String modelId = context.get(FirstDropdownKey).toString();
            String propertyId = context.get(SecodDropdownKey).toString();

            if (StringUtils.hasText(modelId)) {
                searchParam.setModelId(modelId);
                List<InstanceInfo> instanceInfoList = instanceService.selectList(searchParam);
                if (StringUtils.hasText(propertyId) && null != instanceInfoList) {
                    for (InstanceInfo instanceInfo : instanceInfoList) {
                        InstanceInputOption inputOption = new InstanceInputOption(instanceInfo.getId(), instanceInfo.getValue(propertyId).toString());
                        list.add(inputOption);
                    }
                } else {
                    CustomModelServiceImpl customModelService = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
                    List<ModelInfo> modelInfos = customModelService.findAllList();
                    for (ModelInfo modelInfo : modelInfos) {
                        InstanceInputOption inputOption = new InstanceInputOption(modelInfo.getId(), modelInfo.getModelName());
                        list.add(inputOption);
                    }
                }
            }
        }

        return list;
    }


    /**
     * 获取实例数据中外部关联单选的匹配字段
     *
     * @param key
     * @param val
     * @param instanceId
     * @return
     */
    @Override
    public Map<String, Object> getRelationFieldId(String key, Object val, String instanceId, String replace) {
        Map ms = new HashMap();
        if (val != null && val instanceof Map) {
            Map mapInfo = (Map) val;
            Object relationId = mapInfo.get(relationIdKey);
            if (instanceId.equals(relationId)) {
                mapInfo.put(relationNameKey, replace);
                ms.put(key, mapInfo);
                return ms;
            }
        }
        return null;
    }

    @Override
    public Object getRelationName(String key, Object val, String instanceId) {
        Map ms = new HashMap();
        if (val != null && val instanceof Map) {
            Map mapInfo = (Map) val;
            Object relationName = mapInfo.get(relationNameKey);
            return relationName;
        }
        return null;
    }

    @Override
    public void refresh() {
        finalList.clear();
    }

    @Override
    public Object readValue(Object val, Map<String, Object> context) {
        if (val != null && val instanceof Map) {
            String jsonString = JSONObject.toJSONString(val);
            return jsonString;
        }
        return null;
    }

    @Override
    public Object lookValue(Object val, Map<String, Object> context) {
        return readValue(val, context);
    }

    @Override
    public Object exportValue(Object val, Map<String, Object> context) {
        String str = "";
        Set<String> list = new HashSet<>();
        if (val != null && val instanceof Map) {
            Map map = (Map) val;
            String relationName = strValueConvert(map.get(relationNameKey));
            list.add(relationName);
        }
        if (CollectionUtils.isNotEmpty(list)) {
            str = String.join(",", list);
        }
        return str;
    }

    @Override
    public boolean tableHeaderInfo(Map ms, PropertyInfo propertyInfo, List<String> labelNames, List<String> labelId) throws Exception {
        //导出表头数据时，表头字段的id和名称不能同时重复
        if ((labelId != null && !labelId.contains(propertyInfo.getId())) && (labelNames != null && !labelNames.contains(ms.get(nameKey)))) {
            ms.put(typeKey, PropertyTypeExtSingle.ID);
            Set<String> instanceNames = new HashSet<>();
            if (propertyInfo.getPropertyTypeRef() != null) {
                PropertyTypeRef propertyTypeRef = propertyInfo.getPropertyTypeRef();
                labelId.add(propertyInfo.getId());
                Map<String, Object> context = propertyTypeRef.getContext();
                CmdbServiceManage cmdbServiceManage = SpringUtils.getBean(CmdbServiceManage.class);
                InstanceViewImpl instanceView = (InstanceViewImpl) cmdbServiceManage.getModelService(InstanceViewImpl.ID);
                PropertyRelationInfo relationPropertyInfo = new PropertyRelationInfo();
                if (context != null) {
                    Object relationModelId = context.get(relationModelIdKey);
                    Object relationPropertyId = context.get(relationPropertyIdKey);
                    Object linkPropertyId = context.get(linkPropertyIdKey);
                    Object linkTargetPropertyId = context.get(linkTargetPropertyIdKey);
                    relationPropertyInfo.setRelationModelId(strValueConvert(relationModelId));
                    relationPropertyInfo.setRelationPropertyId(strValueConvert(relationPropertyId));
                    relationPropertyInfo.setLinkPropertyId(strValueConvert(linkPropertyId));
                    relationPropertyInfo.setLinkTargetPropertyId(strValueConvert(linkTargetPropertyId));
                }
                List<MwRelationInstanceParam> selectDataByRelation = instanceView.getSelectDataByRelation(relationPropertyInfo);
                Set<String> selectDataList = new HashSet<>();
                List<MwRelationInstanceParam> linkDataList = new ArrayList<>();
                for (MwRelationInstanceParam mwRelationInstanceParam : selectDataByRelation) {
                    if (!Strings.isNullOrEmpty(mwRelationInstanceParam.getRelationName()) && !Strings.isNullOrEmpty(mwRelationInstanceParam.getRelationId())) {
                        selectDataList.add(mwRelationInstanceParam.getRelationName());
                        if (StringUtils.hasText(mwRelationInstanceParam.getLinkPropertyName())) {
                            mwRelationInstanceParam.setLinkTargetPropertyId(relationPropertyInfo.getLinkTargetPropertyId());
                            linkDataList.add(mwRelationInstanceParam);
                        }
                    }
                }

                ms.put(selectDataKey, new ArrayList<>(selectDataList));
                if (!linkDataList.isEmpty()) {
                    ms.put(linkDataKey, linkDataList);
                }
                return true;
            }
        }
        return false;
    }


    /**
     * 获取新增字段所需要的配置数据
     *
     * @param val
     * @param context
     * @return
     */
    @Override
    public Object getDefaultInputValue(Object val, Map<String, Object> context) {
        if (context != null) {
            return context;
        }
        return null;
    }

    @Override
    public Object getDataValue(ImportContextParam contextParam) throws Exception {
        CmdbServiceManage cmdbServiceManage = SpringUtils.getBean(CmdbServiceManage.class);
        InstanceServiceImpl modelService = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);

        MwImportResultParam resultParam = new MwImportResultParam();
        List<ModelExportDataInfoParam> list = contextParam.getListInfos();
        ModelExportDataInfoParam importParam = contextParam.getParam();
        //属性id
        String relationModelId = importParam.getRelationModelId();
        String message = "";
        //属性名称
        String tableName = importParam.getTableName();
        Object cellValue = importParam.getCellValue();
        Map<String, Object> matchMap = new HashMap<>();
        importCheckInfo(resultParam, contextParam, matchMap);

        log.info(tableName + ":extSingle::" + cellValue);

        List<InstanceInfo> instanceInfoList = new ArrayList<>();
        if (finalList == null || finalList.size() == 0 || !finalList.containsKey(relationModelId)) {
            instanceInfoList = modelService.doListByModelIdsNotAuth(Arrays.asList(relationModelId));
            finalList.put(relationModelId, instanceInfoList);
        } else {
            instanceInfoList = finalList.get(relationModelId);
        }
        Map<String, String> instanceNameById = instanceInfoList.stream().filter(s -> !Strings.isNullOrEmpty(strValueConvert(s.getData().get(InStanceNameKey)))).collect(Collectors.toMap(s -> strValueConvert(s.getData().get(InStanceNameKey)), s -> s.getId(), (
                value1, value2) -> {
            return value2;
        }));

        String cellValStr = strValueConvert(cellValue).trim();
        MwRelationInstanceParam relationParam = new MwRelationInstanceParam();
        if (!Strings.isNullOrEmpty(cellValStr)) {
            if (instanceNameById != null && instanceNameById.containsKey(cellValStr)) {
                String relationId = instanceNameById.get(cellValStr);
                relationParam.setRelationId(relationId);
                relationParam.setRelationPropertyId(mwInstanceNameKey);
                relationParam.setRelationName(cellValStr);
            } else {
                resultParam.setMessage(tableName + ":" + cellValue + "不存在");
            }
            Map map = ListMapObjUtils.beanToMap(relationParam);
            resultParam.setCellValue(map);
        }
        return resultParam;
    }
}
